home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Directorty Opus 5 - Magellan
/
Opus 5 - Magellan.iso
/
Extras
/
hotlist_source
/
source
/
ResourceNodes.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-10-02
|
15KB
|
383 lines
/*######################################################################################
## ResourceNode Functions & Structures, by Leo Davidson ##
## Functions for easy allocation, openning, closing, freeing, etc. ##
## ##
## This version uses the memory pool routines in dopus5.library, not the exec ones. ##
## ##
## Tabsize: 4 -- Amiga-specific -- Compile with SAS/C. ##
########################################################################################
$VER: ResourceNodes.c 1.2 (2.10.96)
All routines take a pointer to a ResNode_Data structure. Initially, this
should be all NULLs except for poolhead which must be set up as the Header
for a memory pool. MEMF_CLEAR *must* be turned on for this pool.
It is up to you to free the pool once you're finished using ResNodes.
Other routines are free to use the pool, but if you have more than one pointer
to it, make sure they all get NULLed when the pool is freed.
All close/free/etc. routines should be safe to call when nothing needs to be
closed/freed/etc.
****************************************************************************************
Although these routines and related structures are more-or-less stand alone, the
intention is that a customised version of them will be used for each project. This
means that one isn't tied down by forced compatibility with other situations and
environments.
***************************************************************************************/
#include "hotlist.module.h"
/*====================================================================================-.
|| Optional Functions ||
`-====================================================================================*/
#define ResNodes_Allocate
#define ResNodes_Lock
#define ResNodes_Examine
//#define ResNodes_Open
//#define ResNodes_DeleteFile
/**************************************************************************************/
/*= CreateResNode() ==================================================================-.
|| Attempts to allocate a new ResNode structure. Returns pointer to new, cleared ||
|| ResNode, or NULL on failure. Updates the linked list of ResNodes. ||
`-====================================================================================*/
ResNode *createResNode(ResNode_Data *rnd)
{
ResNode *newResNode;
if ( newResNode = AllocMemH(rnd->poolhead,sizeof(ResNode)) )
{
newResNode->rn_Next = rnd->resnode_base; // Update list pointers
if (rnd->resnode_base)
rnd->resnode_base->rn_Prev = newResNode;
rnd->resnode_base = newResNode;
}
return newResNode;
}
/*= DeleteResNode() ==================================================================-.
|| Delete a ResNode and all free all things connected with it. ||
|| You should not use the ResNode pointer's value again after calling this routine. ||
|| ||
|| Note: Failure to close/deallocate/whatever anything may result in a requester to ||
|| the user but will not cause a different return value. ||
`-====================================================================================*/
void deleteResNode(ResNode_Data *rnd, ResNode *doomedResNode)
{
if (doomedResNode)
{
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* Insert calls to new close/deallocate/whatever functions here. */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
#ifdef ResNodes_Lock
unlockFileResNode(rnd,doomedResNode);
#endif
#ifdef ResNodes_Examine
freeFIBResNode(rnd,doomedResNode);
#endif
#ifdef ResNodes_Open
closeFileResNode(rnd,doomedResNode);
#endif
#ifdef ResNodes_DeleteFile
// Only automatically delete the file if rn_TempFile is set.
if (doomedResNode->rn_TempFile)
deleteFileResNode(rnd,doomedResNode);
#endif
// Deallocation must be done AFTER the file has been deleted because the filename
// may be allocated in the same ResNode!
#ifdef ResNodes_Allocate
freeMemResNode(rnd,doomedResNode);
#endif
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
// Unlink it from the list.
if (doomedResNode->rn_Prev)
(doomedResNode->rn_Prev->rn_Next) = doomedResNode->rn_Next;
else
rnd->resnode_base = doomedResNode->rn_Next; // If no Prev it's head of the list.
if (doomedResNode->rn_Next)
(doomedResNode->rn_Next->rn_Prev) = doomedResNode->rn_Prev;
// Free the memory for the ResNode itself.
FreeMemH(doomedResNode);
}
}
/*= DeleteAllResNodes() ==============================================================-.
|| Delete ALL ResNodes and free all things connected with them. ||
`-====================================================================================*/
void deleteAllResNodes(ResNode_Data *rnd)
{
while (rnd->resnode_base)
deleteResNode(rnd,rnd->resnode_base);
}
#ifdef ResNodes_Allocate
/*= AllocMemResNode() ================================================================-.
|| Allocate some memory for a ResNode. ||
|| Returns pointer to allocated memory, or NULL on failure. ||
|| Memory will be cleared automatically. ||
`-====================================================================================*/
void *allocMemResNode(ResNode_Data *rnd,ResNode *daddyResNode,ULONG memSize)
{
void *amrn_return = NULL;
if (daddyResNode->rn_Mem)
{
// Should never allocate twice for one ResNode.
informUser(rnd->data, TEXT_INTERNAL_ERROR, FALSE, NULL);
}
else
{
if ((daddyResNode->rn_Mem) = AllocMemH(rnd->poolhead,memSize))
(daddyResNode->rn_Size) = memSize;
else
(daddyResNode->rn_Size) = 0;
amrn_return = (daddyResNode->rn_Mem);
}
return (amrn_return);
}
//--- Part of #ifdef above ---
/*= AllocNewResNode() ================================================================-.
|| Create a new ResNode and Allocate memory for it. ||
|| Returns NULL on failure. ||
`-====================================================================================*/
ResNode *allocNewResNode(ResNode_Data *rnd,ULONG memSize)
{
ResNode *babyResNode;
if (babyResNode = createResNode(rnd))
{
if (!(allocMemResNode(rnd,babyResNode,memSize)))
{
deleteResNode(rnd,babyResNode);
babyResNode = NULL;
}
}
return babyResNode;
}
//--- Part of #ifdef above ---
/*= FreeMemResNode() =================================================================-.
|| Free memory allocated for a ResNode. ||
|| Resets rn_Mem and rn_Size to NULL. ||
`-====================================================================================*/
void freeMemResNode(ResNode_Data *rnd,ResNode *dietResNode)
{
if (dietResNode->rn_Mem) // Don't free if nothing to free).
FreeMemH(dietResNode->rn_Mem);
dietResNode->rn_Size = (ULONG)(dietResNode->rn_Mem = NULL);
}
#endif
#ifdef ResNodes_Lock
/*= lockFileResNode() ================================================================-.
|| Attempts to lock the ResNode's file (rn_Name) with the given mode. ||
|| If the file is in use it will try up to RN_INUSE_RETRIES times, waiting ||
|| RN_INUSE_DELAY seconds between each try. ||
|| Lockmode should be either ACCESS_READ or ACCESS_WRITE. ||
|| Returns the lock, or NULL on failure. ||
`-====================================================================================*/
BPTR lockFileResNode(ResNode_Data *rnd,ResNode *rn,LONG lockmode)
{
BPTR lfrn_return = NULL;
int i;
// Internal error if no ResNode, no filename or already locked.
if ( (!(rn)) || (!(rn->rn_Name)) || (rn->rn_Lock) )
informUser(rnd->data, TEXT_INTERNAL_ERROR, NULL, NULL);
else
{
i = 0;
while ( (i <= RN_INUSE_RETRIES) && \
( !(rn->rn_Lock = Lock(rn->rn_Name,lockmode)) ) )
{
if (IoErr() != ERROR_OBJECT_IN_USE)
i = RN_INUSE_RETRIES + 1; // Don't try any more times.
else
{
i++;
Delay(50 * RN_INUSE_DELAY);
}
}
lfrn_return = (rn->rn_Lock);
}
return(lfrn_return);
}
//--- Part of #ifdef above ---
/*= unlockFileResNode() ==============================================================-.
|| Frees the ResNode's file lock, if it has one. ||
|| Passing a NULL ResNode or a ResNode with no lock is harmless. ||
`-====================================================================================*/
void unlockFileResNode(ResNode_Data *rnd,ResNode *lockedResNode)
{
if ( (lockedResNode) && (lockedResNode->rn_Lock) )
{
UnLock(lockedResNode->rn_Lock);
lockedResNode->rn_Lock = NULL;
}
}
#endif
#ifdef ResNodes_Examine
/*= examineResNode() =================================================================-.
|| Attempts to allocate and fill-in the FileInfoBlock (rn_FIB) for a ResNode. ||
|| If the ResNode doesn't have a file lock already one will be obtained in READ mode ||
|| (this requires a valid filename in the ResNode). ||
|| If anything fails, memory allocated for the FIB will be freed and the lock, if ||
|| created by this routine, will be freed. ||
|| Returns pointer to FIB, or NULL on failure. ||
`-====================================================================================*/
struct FileInfoBlock *examineResNode(ResNode_Data *rnd,ResNode *rn)
{
BPTR wegotlock = NULL;
void *ern_return = NULL;
// Internal error if no ResNode, no filename or already examined.
if ( (!(rn)) || (!(rn->rn_Name)) || (rn->rn_FIB) )
informUser(rnd->data, TEXT_INTERNAL_ERROR, NULL, NULL);
else
{
// First, allocate a File Info Block.
if (rn->rn_FIB = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,NULL))
{
// If there isn't a lock, get one in READ mode and remember that this
// routine got the lock so it'll get freed if the Examine() fails.
if ( (rn->rn_Lock) || (wegotlock = lockFileResNode(rnd,rn,ACCESS_READ)) )
{
if ( !(Examine(rn->rn_Lock,rn->rn_FIB)) )
{
// If we couldn't do the Examine(), free what we allocated.
FreeDosObject(DOS_FIB,rn->rn_FIB);
(rn->rn_FIB) = NULL;
if (wegotlock)
unlockFileResNode(rnd,rn);
}
}
// If we couldn't do the Lock(), free what we allocated.
else
{
FreeDosObject(DOS_FIB,rn->rn_FIB);
(rn->rn_FIB) = NULL;
}
}
ern_return = (rn->rn_FIB);
}
return(ern_return);
}
//--- Part of #ifdef above ---
/*= freeFIBResNode() =================================================================-.
|| Frees ResNode's FileInfoBlock (rn_FIB). ||
|| Does *NOT* unlock the ResNode's lock, even if examineResNode got the lock. ||
|| Passing a NULL ResNode or a ResNode with no FIB is harmless. ||
`-====================================================================================*/
void freeFIBResNode(ResNode_Data *rnd,ResNode *rn)
{
if ( (rn) && (rn->rn_FIB) )
{
FreeDosObject(DOS_FIB,rn->rn_FIB);
(rn->rn_FIB) = NULL;
}
}
#endif
#ifdef ResNodes_Open
/*= openFileResNode() ================================================================-.
|| Attempts to open the ResNode's file (using rn_Name as the filename). ||
|| mode must be MODE_OLDFILE, MODE_NEWFILE, or MODE_READWRITE (shared but can create).||
|| If the file is in use it will try up to RN_INUSE_RETRIES times, waiting ||
|| RN_INUSE_DELAY seconds between each try. ||
|| Returns file handle, or NULL on failure. ||
||------------------------------------------------------------------------------------||
|| Note that it is safe to open a ResNode file where the filename is in rn_Mem, too, ||
|| even if you set rn_TempFile, as ResNode memory is freed *after* the file is ||
|| deleted (if required) in deleteResNode(). Of course, you must make sure you don't ||
|| free the filename memory if the file will be deleted later explicitly by you or ||
|| implicitly by deleteResNode(). ||
`-====================================================================================*/
BPTR openFileResNode(ResNode_Data *rnd,ResNode *rn,LONG mode)
{
BPTR ofrn_return = NULL;
int i;
// Internal error if no ResNode, no filename or already openned.
if ( (!(rn)) || (!(rn->rn_Name)) || (rn->rn_FHandle) )
informUser(rnd->data, TEXT_INTERNAL_ERROR, NULL, NULL);
else
{
i = 0;
while ( (i <= RN_INUSE_RETRIES) && \
( !((rn->rn_FHandle) = Open(rn->rn_Name,mode)) ) )
{
if (IoErr() != ERROR_OBJECT_IN_USE)
i = RN_INUSE_RETRIES + 1; // Don't try any more times.
else
{
i++;
Delay(50 * RN_INUSE_DELAY);
}
}
ofrn_return = (rn->rn_FHandle);
}
return(ofrn_return);
}
//--- Part of #ifdef above ---
/*= closeFileResNode() ===============================================================-.
|| Closes the ResNode's file. ||
|| Doesn't bother checking whether or not it failed. (What's it meant to do if it ||
|| does, huh?) ||
|| Passing a NULL ResNode or a ResNode with NULL file handle is harmless. ||
`-====================================================================================*/
void closeFileResNode(ResNode_Data *rnd,ResNode *rn)
{
if ( (rn) && (rn->rn_FHandle) )
{
Close(rn->rn_FHandle);
(rn->rn_FHandle) = NULL;
}
}
#endif
#ifdef ResNodes_DeleteFile
/*= deleteFileResNode() ==============================================================-.
|| Deletes the ResNode's file (rn_Name). ||
|| This routine will only be called automatically on ResNodes with rn_TempFile set. ||
|| Passing a NULL ResNode or a ResNode with no filename is harmless. ||
|| Passing a ResNode with rn_Name pointing to invalid/freed memory is not! ||
|| If the file is in use it will try up to RN_INUSE_RETRIES times, waiting ||
|| RN_INUSE_DELAY seconds between each try. ||
|| If the file cannot be deleted nothing special will happen and the file'll be left. ||
||------------------------------------------------------------------------------------||
|| Note that it is safe to open a ResNode file where the filename is in rn_Mem, too, ||
|| even if you set rn_TempFile, as ResNode memory is freed *after* the file is ||
|| deleted (if required) in deleteResNode(). Of course, you must make sure you don't ||
|| free the filename memory if the file will be deleted later explicitly by you or ||
|| implicitly by deleteResNode(). ||
`-====================================================================================*/
void deleteFileResNode(ResNode_Data *rnd,ResNode *rn)
{
int i;
if ( (rn) && (rn->rn_Name) )
{
i = 0;
while ( (i <= RN_INUSE_RETRIES) && (!(DeleteFile(rn->rn_Name))) )
{
if (IoErr() != ERROR_OBJECT_IN_USE)
i = RN_INUSE_RETRIES + 1; // Don't try any more times.
else
{
i++;
Delay(50 * RN_INUSE_DELAY);
}
}
}
}
#endif